package co.yixiang.mall.biz.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.common.core.utils.FileUtil;
import co.yixiang.common.mproot.common.service.impl.BaseServiceImpl;
import co.yixiang.common.redis.utils.RedisKey;
import co.yixiang.common.redis.utils.RedisUtils;
import co.yixiang.mall.biz.user.service.YxSystemUserLevelService;
import co.yixiang.mall.biz.user.service.YxUserService;
import co.yixiang.mall.common.mall.dto.YxMemberRankingQueryCriteria;
import co.yixiang.mall.common.mall.dto.YxSystemUserLevelQueryCriteria;
import co.yixiang.mall.common.shop.domain.YxSystemUserLevel;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import co.yixiang.mall.biz.user.mapper.UserMapper;
import co.yixiang.mall.biz.user.service.YxMemberService;
import co.yixiang.mall.common.mall.domain.YxUser;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.collections4.CollectionUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static org.apache.ibatis.ognl.OgnlOps.convertValue;


/**
 * @author Administrator
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class YxMemberServiceImpl extends BaseServiceImpl<UserMapper, YxUser> implements YxMemberService {


    @Autowired
    private RedisUtils redisUtils;

    /*会员数据*/
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private YxUserService yxUserService;

    /*用户等级*/
    @Autowired
    private YxSystemUserLevelService yxSystemUserLevelService;


    @Override
    public void download(YxMemberRankingQueryCriteria criteria, HttpServletResponse response) {

        try {
            PageInfo<YxUser> yxUserPageInfo = queryMember(criteria);
            List<YxUser> yxUsers = yxUserPageInfo.getList();


            List<Map<String, Object>> list = new ArrayList<>();

            for (YxUser user : yxUsers) {
                Map<String, Object> map = new HashMap<>();
                map.put("用户id", user.getUid());
                map.put("用户账户", user.getUsername());
                map.put("用户密码", user.getPassword());
                map.put("真实姓名", user.getRealName());
                map.put("生日", user.getBirthday());
                map.put("身份证号码", user.getCardId());
                map.put("用户备注", user.getMark());
                map.put("合伙人id", user.getPartnerId());
                map.put("用户分组id", user.getGroupId());
                map.put("用户昵称", user.getNickname());
                map.put("用户头像", user.getAvatar());
                map.put("手机号码", user.getPhone());
                map.put("添加ip", user.getAddIp());
                map.put("添加时间", user.getCreateTime());
                map.put("最后一次登录时间", user.getUpdateTime());
                map.put("最后一次登录ip", user.getLastIp());
                map.put("用户余额", user.getNowMoney());
                map.put("佣金金额", user.getBrokeragePrice());
                map.put("用户剩余积分", user.getIntegral());
                map.put("连续签到天数", user.getSignNum());
                map.put("状态", user.getStatus() == 0 ? "禁止" : "正常");
                map.put("等级", user.getLevel());
                map.put("推广员id", user.getSpreadUid());
                map.put("推荐人关联时间", user.getSpreadTime());
                map.put("用户类型", user.getUserType());
                map.put("是否为推广员", user.getIsPromoter() == 0 ? "否" : "是");
                map.put("用户购买次数", user.getPayCount());
                map.put("下级人数", user.getSpreadCount());
                map.put("详细地址", user.getAddres());
                map.put("管理员编号", user.getAdminid());
                map.put("用户登陆类型", user.getLoginType());
                map.put("微信用户json信息", user.getUpdateTime());
                map.put("是否删除", user.getIsDel() == 0 ? "删除" : "未删除");
                map.put("所属层级", user.getUpdateTime());
                map.put("累计金额", user.getUpdateTime());

                list.add(map);
            }

            FileUtil.downloadExcel(list, response);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public PageInfo<YxUser> queryMember(YxMemberRankingQueryCriteria criteria) {
        if (BeanUtil.isNotEmpty(criteria)) {

            List<String> resource = criteria.getResource();
            resource.forEach(res -> {
                if ("等级".equals(res)) {
                    criteria.setLevel(res);
                }
                if ("业绩".equals(res)) {
                    criteria.setCommissionIncome(res);
                }
                if ("佣金金额".equals(res)) {
                    criteria.setPerformance(res);
                }
            });
        }

        PageHelper.startPage(criteria.getPageNumber() + 1, criteria.getPageSize());
        LambdaQueryWrapper<YxUser> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(criteria.getLevel()) && StrUtil.isNotEmpty(criteria.getCommissionIncome()) && StrUtil.isNotEmpty(criteria.getPerformance())) {
            wrapper.orderByAsc(YxUser::getCreateTime).
                    orderByAsc(YxUser::getLevel).
                    orderByAsc(YxUser::getBrokeragePrice).
                    orderByAsc(YxUser::getAccumulative_amount);
        } else if (StrUtil.isNotEmpty(criteria.getLevel()) && StrUtil.isEmpty(criteria.getCommissionIncome()) && StrUtil.isNotEmpty(criteria.getPerformance())) {
            wrapper.orderByAsc(YxUser::getCreateTime).
                    orderByAsc(YxUser::getLevel).
                    orderByAsc(YxUser::getAccumulative_amount);
        } else if (StrUtil.isNotEmpty(criteria.getLevel()) && StrUtil.isEmpty(criteria.getCommissionIncome()) && StrUtil.isEmpty(criteria.getPerformance())) {
            wrapper.orderByAsc(YxUser::getCreateTime).
                    orderByAsc(YxUser::getLevel);
        }else if (StrUtil.isEmpty(criteria.getLevel()) && StrUtil.isNotEmpty(criteria.getCommissionIncome()) && StrUtil.isNotEmpty(criteria.getPerformance())) {
            wrapper.orderByAsc(YxUser::getCreateTime).
                    orderByAsc(YxUser::getBrokeragePrice).
                    orderByAsc(YxUser::getAccumulative_amount);
        }else if (StrUtil.isEmpty(criteria.getLevel()) && StrUtil.isNotEmpty(criteria.getCommissionIncome()) && StrUtil.isEmpty(criteria.getPerformance())) {
            wrapper.orderByAsc(YxUser::getCreateTime).
                    orderByAsc(YxUser::getBrokeragePrice);
        }else if (StrUtil.isEmpty(criteria.getLevel()) && StrUtil.isEmpty(criteria.getCommissionIncome()) && StrUtil.isNotEmpty(criteria.getPerformance())) {
            wrapper.orderByAsc(YxUser::getCreateTime).
                    orderByAsc(YxUser::getAccumulative_amount);
        }else{
            wrapper.orderByAsc(YxUser::getCreateTime);
        }

        PageInfo<YxUser> page = new PageInfo<>(baseMapper.selectList(wrapper));

        return page;
    }


    public static void main(String[] args) {

      /*  Map<Long, YxUser> map = new HashMap<>();

        YxUser yxUser = new YxUser();
        yxUser.setUid(2L);
        yxUser.setPartnerId(3);

        YxUser yxUse = new YxUser();

        yxUse.setUid(3L);
        yxUse.setPartnerId(6);

        map.put(1L, yxUser);
        map.put(2L, yxUser);
        map.put(3L, yxUse);
        map.put(4L, yxUse);

        map.entrySet().stream().map((e) ->
                e.getValue()
        ).collect(Collectors.groupingBy(
                (e) -> e.getPartnerId(),
                Collectors.mapping(
                        (e) -> e.getUid(),
                        Collectors.toList()
                )
        )).forEach((key, value) -> {
            System.err.println(key);
            System.err.println(value);
        });*/

        LinkedList<Long> longs = new LinkedList<>();

        System.err.println(CollUtil.isNotEmpty(longs));

    }

    /**
     * yuan
     * 修改用户的上级
     *
     * @param userUid     修改目标用户的id
     * @param superiorUid 用户的目标上级
     * @return 返回true 成功 false失败
     */
    @Override
    public boolean updateSuperior(Long userUid, Long superiorUid) {
        /*成功失败标识*/
        AtomicBoolean status = new AtomicBoolean(true);
        /*提示*/
        StringBuffer buffer = new StringBuffer();
        /*获取 用户数据 组数据*/
        Map<Long, YxUser> userUidGrouping = getGrouping(userUid);

        /*获取 获取用户要修改的上级数据*/
        YxUser superiorUser = yxUserService.getYxUserId(superiorUid);

        /*以 父级id分组得到每一用户的下级*/
        Map<Integer, List<YxUser>> UnderLevelMap = userUidGrouping.entrySet()
                .stream()
                /*将map的value转换为list*/
                .map((e) -> e.getValue())
                /*使用 父级id 将list分组*/
                .collect(Collectors.groupingBy(
                        (e) -> e.getPartnerId(),
                        /*将分组中的 value 实体类 转换存储*/
                        Collectors.mapping(
                                (e) -> {
                                    YxUser yxUser = new YxUser();
                                    if (userUid.equals(e.getUid())) {
                                        /*如果 是用户本身，还需要修改用户的上级*/
                                        yxUser.setPartnerId(superiorUser.getPartnerId());
                                    }
                                    yxUser.setUid(e.getUid());
                                    /*分组标识 修改为 用户本身 要修改的上级分组标识*/
                                    yxUser.setGroupId(superiorUser.getGroupId());
                                    return yxUser;
                                },
                                /*的list 返回*/
                                Collectors.toList()
                        )
                ));
        /*得到用户的所有下级id*/
        List<YxUser> underLevel = getUnderLevel(UnderLevelMap, new YxUser().setUid(userUid).setGroupId(userUidGrouping.get(userUid).getGroupId()));

        /*批量修改 他与下级的分组标识*/
        boolean b = this.updateBatchById(underLevel, underLevel.size());
        if(!b){
            status.set(b);
            buffer.append("批量修改 他与下级的分组标识不成功，");
        }

        /*删除redis中原本用户本身分组中 他和下级的数据*/
        redisUtils.hdel(RedisKey.YxUser.USER_MAP_GROUPING + userUidGrouping.get(userUid).getGroupId(), underLevel.stream().map((e) -> e.getUid()).collect(Collectors.toList()));

        /*判断 用户要改变的 上级 key是否存在 ，存在 改 不存在不修改*/
        if (redisUtils.hasKey(RedisKey.YxUser.USER_MAP_GROUPING + superiorUser.getGroupId())) {
            List<YxUser> insetList = new ArrayList<>();

            underLevel.forEach((e) -> {
                insetList.add(
                        userUidGrouping.get(e)
                                .setGroupId(superiorUser.getGroupId()));
            });

            /*将用户与它下级的数据添加在，他修改的上级 分组中*/
            insetList.forEach((e) -> {
                boolean hSet = redisUtils.hset(RedisKey.YxUser.USER_MAP_GROUPING + superiorUser.getGroupId(), String.valueOf(e.getUid()), e);
                if (!hSet) {
                    status.set(hSet);
                    buffer.append("更新用户分组有不成功数据，总共更新数据" + underLevel.size() + "条数据，");
                }
            });
        }

        /*下面更新redis 存储String用户类型 单独 数据类型*/
        underLevel.forEach((e) -> {
            /*判断用户String是否存在，存在要改 不存在不修改*/
            if (redisUtils.hasKey(RedisKey.YxUser.USER_ID + e.getUid())) {
                YxUser yxUser = null;
                if (e.getUid().equals(userUid)) {
                    /*如果是当前用户还需要 修改他的上级id*/
                    yxUser = userUidGrouping.get(e.getUid()).setGroupId(superiorUser.getGroupId()).setPartnerId(Math.toIntExact(superiorUid));
                } else {
                    yxUser = userUidGrouping.get(e.getUid()).setGroupId(superiorUser.getGroupId());
                }
                boolean StrSet = redisUtils.set(RedisKey.YxUser.USER_ID + e.getUid(), yxUser);
                if (!StrSet) {
                    status.set(StrSet);
                    buffer.append("更新用户redis字符串不成功。");
                }
            }
        });

        return false;
    }

    /**
     * 获取用户的下级数据
     *
     * @param userMap key 这个用户的id value 这个用户的下级数据
     * @param user    用户的数据
     * @return
     */
    @Override
    public List<YxUser> getUnderLevel(Map<Integer, List<YxUser>> userMap, YxUser user) {

        /*存放 用户下级的*/
        LinkedList<YxUser> returnLongs = new LinkedList<>();

        LinkedList<YxUser> longs = new LinkedList<>();
        /*现将用户的id放进去*/
        longs.add(user);
        /*把他自己的id也放进去*/
        returnLongs.add(user);
        /*不等于 null 就一直插在 这个用户的下级*/
        while (CollUtil.isNotEmpty(longs)) {
            /*删除并返回 list中 第一条数据*/
            YxUser pop = longs.pop();
            /*从map中获取*/
            List<YxUser> list = userMap.get(pop.getUid());
            /*如果不等于 null 将查找到的数据 存放在longs*/
            if (CollUtil.isNotEmpty(list)) {
                longs.addAll(list);
                returnLongs.addAll(list);
            }
        }
        /*返回数据*/
        return returnLongs;
    }



    /**
     * 获取用户自己的数据和下级人数
     *
     * @param uid 这个用户的id
     * @param status 是查询用户自己的数据还是，他的下级数据 ，1自己数据，2下级数据
     * @return
     */
    @Override
    public List<Map<String,String>> getOneself(Long uid,String status) {

        /*获取用户所在分组的所有数据*/
        Map<Long, YxUser> grouping = getGrouping(uid);

        /*会员等级数据*/
        Map<Integer, YxSystemUserLevel> levelMap = yxSystemUserLevelService.queryAll(new YxSystemUserLevelQueryCriteria())
                .stream().collect(Collectors.toMap(
                        (e) -> e.getGrade(),
                        (e) -> e,
                        (e1, e2) -> e1
                ));

        /*用户查询用户下级的人数*/
        Map<Long, List<Long>> collect = grouping.entrySet().stream().map((e) -> e.getValue())
                .collect(Collectors.groupingBy(
                        (e) -> Long.valueOf(e.getPartnerId()),
                        Collectors.mapping(
                                (e) -> e.getUid(),
                                Collectors.toList()
                        )
                ));

        /*返回的数据存储盒子*/
        List<Map<String,String>> listMap = new ArrayList<>();

        /*得到用户自己的数据*/
        YxUser yxUser = grouping.get(uid);
        /*拼接数据*/
        StringBuffer buffer = new StringBuffer();

        HashMap<String, String> map = null;

        /*参数等于1返回用户自己的数据*/
        if ("1".equals(status)){
            /*得到用户下级的数量*/
            Integer integer = queryNumber(collect, uid);

            map = new HashMap<>();

            map.put("id", String.valueOf(yxUser.getUid()));

            buffer.append("名称：" + yxUser.getUsername());
            buffer.append(" - ");
            buffer.append("用户等级：" + levelMap.get(yxUser.getLevel()).getName());
            buffer.append(" - ");
            buffer.append("用户电话：" + yxUser.getPhone());
            buffer.append(" - ");
            buffer.append("团队人数：" + integer);

            map.put("name", buffer.toString());

            /*如果用户没有下级，前端就不显示 加载 下级数据*/
            if (integer.equals(0)) {
                map.put("leaf", "true");
            }else{
                map.put("leaf", "false");
            }

            listMap.add(map);

            return listMap;
        }

        /*=======如果上面没有返回证明是要查找下级的数据=======*/

        /*获取这个用户下级人员 的id*/
        List<Long> longs = collect.get(uid);
        longs.forEach((e) -> {

            HashMap<String, String> longsMap = new HashMap<>();

            /*得到用户下级的数量*/
            Integer integer = queryNumber(collect,e);

            /**/
            buffer.append("名称：" + grouping.get(e).getUsername());
            buffer.append(" - ");
            buffer.append("用户等级：" + levelMap.get(grouping.get(e).getLevel()).getName());
            buffer.append(" - ");
            buffer.append("用户电话：" + grouping.get(e).getPhone());
            buffer.append(" - ");
            buffer.append("团队人数：" + integer);

            longsMap.put("name", buffer.toString());
            /*用户id*/
            longsMap.put("id", String.valueOf(e));
            /*如果用户没有下级，前端就不显示 加载 下级数据*/
            if (integer.equals(0)) {
                longsMap.put("leaf", "true");
            }else{
                longsMap.put("leaf", "false");
            }

            listMap.add(longsMap);

            /*清空原有的数据*/
            buffer.delete(0,buffer.length());

        });

        return listMap;
    }


    /**
     * yuan
     * 封装查询下级数量
     *
     * @param map 当前用户所在组中所有数据
     * @param uid 当前用户 数据
     * @return
     */
    @Override
    public Integer queryNumber(Map<Long, List<Long>> map, Long uid) {
        /*累计金额*/
        Integer number = 0;

        /*下级数据*/
        LinkedList<Long> yxUserList = new LinkedList<>();

        /*添加当前 用户本身的数据*/
        yxUserList.add(uid);
        /* 循环 当前用户下级数据*/
        while (CollectionUtils.isNotEmpty(yxUserList)) {
            /*删除并返回 list中的第一条数据*/
            Long pop = yxUserList.pop();
            /*获取 删除并返回第一条数据的id 查找他的下级 */
            List<Long> yxUsers = map.get(pop);
            /*计算 下级累计金额*/
            number++;
            /*判断不等于 null*/
            if (CollectionUtils.isNotEmpty(yxUsers)) {
                /*加入list继续查找下级*/
                yxUserList.addAll(yxUsers);
            }
        }
        /*返回累计的进金额*/
        return --number;

    }

    /**
     * yuan
     * 查询 这个用户在组的成员所有数据
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public Map<Long, YxUser> getGrouping(Long userId) {
        /*获取用户数据*/
        YxUser yxUserId = yxUserService.getYxUserId(userId);
        /*从redis中获取 组数据*/
        Map<Object, Object> hmGet = redisUtils.hmget(RedisKey.YxUser.USER_MAP_GROUPING + yxUserId.getGroupId());
        /*返回的数据*/
        Map<Long, YxUser> returnUserMap = new HashMap<>();

        /*如果没有 从数据库中读取*/
        if (CollUtil.isEmpty(hmGet)) {
            /**
             * 防止 缓存穿透
             * 当有 一万个人同时进入方法，一万个人等待在synchronized这里，只有一个人可以进入 synchronized块中，
             * 进入后在获取数据判断是不是空如果是 进入数据库查找数据，后把数据添加在redis中，过后，第二个人进入，在
             * 从redis获取数据判断一次空，第一个人获取到数据后已经存入redis，就能拿到数据，就不会再次进入
             * if(CollUtil.isEmpty(hmGet))中。
             */
            synchronized (this) {
                /*在获取一次*/
                hmGet = redisUtils.hmget(RedisKey.YxUser.USER_MAP_GROUPING + yxUserId.getGroupId());
                /*还等于空从 数据库中获取*/
                if (CollUtil.isEmpty(hmGet)) {
                    /*数据库中获取*/
                    List<YxUser> yxUsers = userMapper.selectList(new QueryWrapper<YxUser>().eq("group_id", yxUserId.getGroupId()));
                    /*获取数据库不等于null 添加redis中*/
                    if (CollectionUtil.isNotEmpty(yxUsers)) {
                        /*将数据转化为map类型 id为key 具体信息 value*/
                        Map<String, Object> userMap = yxUsers.stream().collect(Collectors.toMap(
                                (e) -> String.valueOf(e.getUid()),
                                (e) -> e,
                                (e1, e2) -> e1
                        ));
                        /*添加返回数据*/
                        returnUserMap.putAll(
                                yxUsers.stream().collect(Collectors.toMap(
                                        (e) -> e.getUid(),
                                        (e) -> e,
                                        (e1, e2) -> e1
                                )));
                        /*添加redis*/
                        redisUtils.hmset(RedisKey.YxUser.USER_MAP_GROUPING + yxUserId.getGroupId(), userMap, redisUtils.failureTime);
                    }
                }
            }

        }
        /*如果 returnUserMap 等于空 ，证明在redis中获取，将value object类型转换 yxUser 实体类*/
        if (CollUtil.isEmpty(returnUserMap)) {
            /*遍历转换*/
            hmGet.forEach((key, value) -> {
                YxUser yxUser = new ObjectMapper().convertValue(value, YxUser.class);
                returnUserMap.put(Long.valueOf(key.toString()), yxUser);
            });
        }

        return returnUserMap;
    }







/*

    @Override
    public Object getMember(YxMemberRankingQueryCriteria qc) {
        return null;
    }

    @Override
    public Map<String, Object> getAll(YxMemberRankingQueryCriteria qc, Pageable pageable) {
        getPage(pageable);
        PageInfo<YxUser> page = new PageInfo<>(queryAll(qc));
        Map<String, Object> map = new LinkedHashMap<>(2);
        map.put("content", generator.convert(page.getList(), YxUser.class));
        map.put("totalElements", page.getTotal());
        return map;
    }

    @Override
    public List<YxUser> queryAll(YxMemberRankingQueryCriteria criteria) {

        return baseMapper.selectList(QueryHelpPlus.getPredicate(YxUser.class, criteria));

    }
*/


}
